//
// Created by bangsun on 2022/10/15.
//

#ifndef COROUTINE_LZY_SWITCH_H
#define COROUTINE_LZY_SWITCH_H


#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"


#ifndef USE_64_ENV
#define WORD_PTR int
#define WORD int
#define WORD_SIZE 4
#else
#define WORD_PTR long
#define WORD long
#define WORD_SIZE 8
#endif

#define STACK_SIZE (1<<13) // 8kB



// | <self area> |eflags|eax|edx|ecx|ebx|esi|edi|ebp|<eip>(prev)
//               -> stack index increase
//                            stack grow direction <-

#define ENTRY_PARAM_ARG_OFFSET 0
#define ENTRY_LOUTINE_ARG_OFFSET 1
#define TERMINATE_ENTRY_OFFSET 2
#define RETADDR_OFFSET 3
#define EBP_OFFSET 4
#define EDI_OFFSET 5
#define ESI_OFFSET 6
#define EBX_OFFSET 7
#define ECX_OFFSET 8
#define EDX_OFFSET 9
#define EAX_OFFSET 10
#define EFLAGS_OFFSET 11

#define ESP_MOVE_OFFSET 11

#define INIT_STATE (1<<0)
#define READY_STATE (1<<1)
#define RUNNING_STATE (1<<2)
#define BLOCKING_STATE (1<<3)
#define DONE_STATE (1<<4)
#define KILLED_STATE (1<<5)

#define MAX_LOUTINE 1024

#define TERMINATE_ENTRY 100

#define LID int


typedef struct Loutine {
    WORD_PTR stack;
    int id;
    int state;
    WORD_PTR stacktop;

    void (*entry)(void *);

    int time_slot;
    void* arg;

    struct Loutine* to_kill;
} Loutine;


void init_loutine_environment();

void init_loutine(Loutine* loutine, void(*entry)(void *), void *arg);

Loutine* create_loutine(void(*entry)(void *), void *arg);

void free_loutine(void *loutine);

void switch_to_loutine(Loutine *next);

void reschedule_gmp(Loutine *curr, Loutine *next);


void func1();

void func2();

#endif //COROUTINE_LZY_SWITCH_H
